package com.biodiv.miracle.ioc.processor;

import com.biodiv.miracle.support.annotation.Bean;
import com.biodiv.miracle.support.utils.MiracleUtils;

import java.lang.reflect.Method;

/**
 * @Author: tianquan
 * @@date: 2024-09-30  09:18
 * @Description: 解析@Bean注解,通过反射调用这些方法，并将返回的对象注册到容器中
 */
public class InstanceBeanPostProcessor implements InjectBeanPostProcessor {

    /**
     * 处理注入逻辑
     * 遍历指定bean的所有方法，寻找带有@Bean注解的方法并执行
     *
     * @param bean 要处理的bean实例
     */
    @Override
    public void inject(Object bean) {
        // 获取当前bean的类
        Class<?> aClass = bean.getClass();
        // 获取类中所有声明的方法
        Method[] declaredMethods = aClass.getDeclaredMethods();
        for (Method method : declaredMethods) {
            // 检查方法是否带有@Bean注解
            Bean instance = method.getAnnotation(Bean.class);
            if (instance == null) {
                continue;
            }
            method.setAccessible(true);
            // 遍历拿到要入参要的Bean
            int parameterCount = method.getParameterCount();
            Class<?>[] parameterTypes = method.getParameterTypes();
            Object[] args = new Object[parameterCount];
            for (int i = 0; i < parameterCount; i++) {
                // 使用MiracleUtils工具类获取参数类型的Bean实例
                args[i] = MiracleUtils.getBean(parameterTypes[i]);
                // 如果找不到对应的Bean实例，抛出异常
                if (args[i] == null) {
                    throw new RuntimeException("can not find bean is " + parameterTypes[i].getName());
                }
            }
            try {
                // 调用方法,拿到要注入的对象
                Object object = method.invoke(bean, args);
                // 获取方法返回类型生成bean的名字,注册到容器中
                Class<?> returnType = method.getReturnType();
                String beanName = MiracleUtils.createBeanName(returnType);
                MiracleUtils.registerBean(beanName, object);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;
    }
}

